package top.healthylife.gateway.platform.jg.api.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import top.healthylife.basics.utils.exception.BusinessException;
import top.healthylife.gateway.core.util.SystemConfigUtils;
import top.healthylife.gateway.dto.request.req.ApiReqDto;
import top.healthylife.gateway.platform.jg.api.config.SystemConfig;
import top.healthylife.gateway.platform.jg.dto.annotation.AutoUnderline;
import top.heathylife.gateway.common.po.RecordRequestInfo;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 极光统一接口调用工具类
 *
 * @author gwx
 * @date 2021/9/8
 */
@Slf4j
public class JGHttpUtil {

    private final static String proUrl = "https://api.data.jiguang.cn";

    public static final Integer SUCCESS = 2000;
    public static final Integer NO_DATA = 2001;


    static Map<Integer,String> codeMap = new HashMap<>();

    static {
        codeMap.put(2000,"成功查询返回");
        codeMap.put(2001,"成功查询,但未查到数据");
        codeMap.put(4000,"参数错误");
        codeMap.put(4005,"由于未授权,权限过期,调用次数超次,或调用频率超频等,可收到此返回码");
        codeMap.put(5000,"系统内部异常");
    }

    /**
     * 极光-统一请求入口
     *
     * @param reqDto
     * @param res
     * @param apiName 接口名称
     * @return
     */
    @SneakyThrows
    public static <T> T httpGetRequest(ApiReqDto reqDto, String apiName, Class<T> res) {
        //获取账号配置信息
        SystemConfig systemConfig = systemConfigInfo(reqDto);
        //鉴权数据
        String basicString = getAuthentication(systemConfig);
        //构造请求参数
        String params = constructRequest(reqDto);
        Map<String, String> headMap = new HashMap<>();
        headMap.put("Authorization", "Basic " + basicString);
        headMap.put("accept", MediaType.APPLICATION_JSON_VALUE);
        String finallyUrl = proUrl + apiName + params;
        RecordRequestInfo.recordRequest(finallyUrl, null, headMap, "get");
        log.info("最终访问地址为:{}", finallyUrl);
        String body = HttpRequest.get(finallyUrl).header("Authorization", basicString)
                .header("accept", "application/json").execute().body();
        if (!StringUtils.isEmpty(body)) {
            JSONObject jsonObject = JSONObject.parseObject(body);
            Integer code = jsonObject.getInteger("code");
            if (code.equals(SUCCESS)) {
               return jsonObject.toJavaObject(res);
            }
            if (code.equals(NO_DATA)) {
                return jsonObject.toJavaObject(res);
            }
            if(codeMap.containsKey(code)){
                throw new BusinessException("极光接口响应异常:{},code码:{}", codeMap.get(code), code);
            }
            String msg = jsonObject.getString("message");
            //其他未知异常
            throw new BusinessException("极光接口响应异常:{},code码:{}", msg ,code);
        }
        throw new BusinessException("极光接口响应异常:响应结果为空");
    }

    //请求参数需要转下划线,判断AutoUnderline注解
    private static String constructRequest(ApiReqDto reqDto) throws Exception {
        String params = "?";
        Class reqClass = reqDto.getClass();
        Field[] fields = reqClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String param = (String) field.get(reqDto);
            if (StringUtils.isEmpty(param)) {
                continue;
            }
            AutoUnderline annotation = field.getAnnotation(AutoUnderline.class);
            if (!ObjectUtil.isEmpty(annotation)) {
                //将驼峰转成下划线
                params += humpToUnderline(field.getName()) + "=" + param + "&";
            } else {
                params += field.getName() + "=" + param + "&";
            }
        }
        //去掉最后的&
        params = params.substring(0, params.length() - 1);
        return params;
    }

    //创建鉴权数据base64(key:secret)
    private static String getAuthentication(SystemConfig systemConfig) {
        // 获取密钥的键值对
        String devKey = systemConfig.getKey();
        String devSecret = systemConfig.getSecret();
        // 密钥键值对加密
        String contactStr = devKey + ":" + devSecret;
        String encode = Base64.encode(contactStr.getBytes());
        return "Basic " + encode;
    }

    /***
     * 驼峰命名转为下划线命名
     * @param para
     *  驼峰命名的字符串
     */
    public static String humpToUnderline(String para) {
        StringBuilder sb = new StringBuilder(para);
        int temp = 0;//偏移量，第i个下划线的位置是 当前的位置+ 偏移量（i-1）,第一个下划线偏移量是0
        for (int i = 0; i < para.length(); i++) {
            if (Character.isUpperCase(para.charAt(i))) {
                sb.insert(i + temp, "_");
                temp += 1;
            }
        }
        return sb.toString().toLowerCase();
    }


    /**
     * 访问日志输出和配置获取
     *
     * @param apiReqDto 入参
     * @return 账号信息
     */
    public static SystemConfig systemConfigInfo(ApiReqDto apiReqDto) {
        //可直接通过工具类获取这个对象
        SystemConfig o = (SystemConfig) SystemConfigUtils.get();
        log.info("请求参数为:{}", JSONObject.toJSONString(apiReqDto));
        log.info("账号信息为:{}", JSONObject.toJSONString(o));
        return o;
    }

}
